//
// Created by liyinbin on 2021/12/26.
//

#include "scylla/api/scylla.h"

namespace scylla {

    status scylla_store::set(const std::string_view &key, const std::string_view &value) {
        return _impl->set(key, value);
    }

    /// get the value of the key, if not exist, set = default nil value.
    status scylla_store::get(const std::string_view &key, std::string *value) {
        return _impl->get(key, value);
    }

    /// set key to hold the string value. if key exist
    status
    scylla_store::set_xx(const std::string_view &key, const std::string_view &value, const int32_t ttl, int32_t *ret) {
        return _impl->set_xx(key, value, ttl, ret);
    }

    /// atomically set key to value and return the old value.
    /// return error when key exist but has no value.
    status
    scylla_store::get_and_set(const std::string_view &key, const std::string_view &value, std::string *old_value) {
        return _impl->get_and_set(key, value, old_value);
    }

    /// sets or clears the bit at offset in the string value stored at key
    status scylla_store::set_bit(const std::string_view &key, size_t offset, int32_t value, int32_t *ret) {
        return _impl->set_bit(key, offset, value, ret);
    }

    /// returns the bit value at offset in the string value stored at key
    status scylla_store::get_bit(const std::string_view &key, size_t offset, int32_t *ret) {
        return _impl->get_bit(key, offset, ret);
    }

    /// sets the given keys to their respective values
    /// multi_set replaces existing values with new values
    status scylla_store::multi_set(const std::vector <key_value> &kvs) {
        return _impl->multi_set(kvs);
    }

    //// Returns the values of all specified keys. For every key
    /// that does not hold a string value or does not exist, the
    /// special value nil is returned
    status scylla_store::multi_get(const std::vector <std::string> &keys,
                                   std::vector <value_status> *vss) {
        return _impl->multi_get(keys, vss);
    }

    /// Set key to hold string value if key does not exist
    /// return 1 if the key was set
    /// return 0 if the key was not set
    status
    scylla_store::set_nx(const std::string_view &key, const std::string_view &value, int32_t *ret, const int32_t ttl) {
        return _impl->set_nx(key, value, ret, ttl);
    }

    /// sets the given keys to their respective values.
    /// multi_set_nx will not perform any operation at all even
    /// if just a single key already exists.
    status scylla_store::multi_set_nx(const std::vector <key_value> &kvs, int32_t *ret) {
        return _impl->multi_set_nx(kvs, ret);
    }

    /// Set key to hold string new_value if key currently hold the give value
    /// return 1 if the key currently hold the give value And override success
    /// return 0 if the key doesn't exist And override fail
    /// return -1 if the key currently does not hold the given value And override fail
    status
    scylla_store::set_vx(const std::string_view &key, const std::string_view &value, const std::string_view &new_value,
                         int32_t *ret, const int32_t ttl) {
        return _impl->set_vx(key, value, new_value, ret, ttl);

    }

    /// delete the key that holds a given value
    /// return 1 if the key currently hold the give value And delete success
    /// return 0 if the key doesn't exist And del fail
    /// return -1 if the key currently does not hold the given value And del fail
    status scylla_store::del_vx(const std::string_view &key, const std::string_view &value, int32_t *ret) {
        return _impl->del_vx(key, value, ret);
    }

    /// Set key to hold string value if key does not exist
    /// return the length of the string after it was modified by the command
    status scylla_store::set_range(const std::string_view &key, int64_t start_offset,
                                   const std::string_view &value, int32_t *ret) {
        return _impl->set_range(key, start_offset, value, ret);
    }

    /// Returns the substring of the string value stored at key,
    /// determined by the offsets start and end (both are inclusive)
    status scylla_store::get_range(const std::string_view &key, int64_t start_offset, int64_t end_offset,
                                   std::string *ret) {
        return _impl->get_range(key, start_offset, end_offset, ret);
    }

    /// If key already exists and is a string, this command appends the value at
    /// the end of the string
    /// return the length of the string after the append operation
    status scylla_store::append(const std::string_view &key, const std::string_view &value, int32_t *ret) {
        return _impl->append(key, value, ret);
    }

    /// Count the number of set bits (population counting) in a string.
    /// return the number of bits set to 1
    /// note: if need to specified offset, set have_range to true
    status scylla_store::bit_count(const std::string_view &key, int64_t start_offset, int64_t end_offset,
                                   int32_t *ret, bool have_offset) {
        return _impl->bit_count(key, start_offset, end_offset, ret, have_offset);
    }

    /// Perform a bitwise operation between multiple keys
    /// and store the result in the destination key
    status scylla_store::bit_op(bit_op_type op, const std::string &dest_key,
                                const std::vector <std::string> &src_keys, int64_t *ret) {
        return _impl->bit_op(op, dest_key, src_keys, ret);
    }

    /// Return the position of the first bit set to 1 or 0 in a string
    /// bit_pos key 0
    status scylla_store::bit_pos(const std::string_view &key, int32_t bit, int64_t *ret) {
        return _impl->bit_pos(key, bit, ret);
    }

    /// bit_pos key 0 [start]
    status scylla_store::bit_pos(const std::string_view &key, int32_t bit,
                                 int64_t start_offset, int64_t *ret) {
        return _impl->bit_pos(key, bit, start_offset, ret);
    }

    /// bit_pos key 0 [start] [end]
    status scylla_store::bit_pos(const std::string_view &key, int32_t bit,
                                 int64_t start_offset, int64_t end_offset,
                                 int64_t *ret) {
        return _impl->bit_pos(key, bit, start_offset, end_offset, ret);
    }

    /// Decrements the number stored at key by decrement
    /// return the value of key after the decrement
    status scylla_store::decr_by(const std::string_view &key, int64_t value, int64_t *ret) {
        return _impl->decr_by(key, value, ret);
    }

    /// Increments the number stored at key by increment.
    /// If the key does not exist, it is set to 0 before performing the operation
    status scylla_store::incr_by(const std::string_view &key, int64_t value, int64_t *ret) {
        return _impl->incr_by(key, value, ret);
    }

    /// Increment the string representing a floating point number
    /// stored at key by the specified increment.
    status scylla_store::incr_by_float(const std::string_view &key, const std::string_view &value, std::string *ret) {
        return _impl->incr_by_float(key, value, ret);
    }

    /// Set key to hold the string value and set key to timeout after a given
    /// number of seconds
    status scylla_store::set_ex(const std::string_view &key, const std::string_view &value, int32_t ttl) {
        return _impl->set_ex(key, value, ttl);
    }

    /// Returns the length of the string value stored at key. An error
    /// is returned when key holds a non-string value.
    status scylla_store::strlen(const std::string_view &key, int32_t *len) {
        return _impl->strlen(key, len);
    }

    ///// hash
    /// Sets field in the hash stored at key to value. If key does not exist, a new
    /// key holding a hash is created. If field already exists in the hash, it is
    /// overwritten.
    status
    scylla_store::hash_set(const std::string_view &key, const std::string_view &field, const std::string_view &value,
                           int32_t *res) {
        return _impl->hash_set(key, field, value, res);
    }

    /// Returns the value associated with field in the hash stored at key.
    /// the value associated with field, or nil when field is not present in the
    /// hash or key does not exist.
    status scylla_store::hash_get(const std::string_view &key, const std::string_view &field, std::string *value) {
        return _impl->hash_get(key, field, value);
    }

    /// Sets the specified fields to their respective values in the hash stored at
    /// key. This command overwrites any specified fields already existing in the
    /// hash. If key does not exist, a new key holding a hash is created.
    status scylla_store::hash_multi_set(const std::string_view &key,
                                        const std::vector <field_value> &fvs) {
        return _impl->hash_multi_set(key, fvs);
    }

    /// Returns the values associated with the specified fields in the hash stored
    /// at key.
    /// For every field that does not exist in the hash, a nil value is returned.
    /// Because a non-existing keys are treated as empty hashes, running HMGET
    /// against a non-existing key will return a list of nil values.
    status scylla_store::hash_multi_get(const std::string_view &key,
                                        const std::vector <std::string> &fields,
                                        std::vector <value_status> *vss) {
        return _impl->hash_multi_get(key, fields, vss);
    }

    /// Returns all fields and values of the hash stored at key. In the returned
    /// value, every field name is followed by its value, so the length of the
    /// reply is twice the size of the hash.
    status scylla_store::hash_get_all(const std::string_view &key,
                                      std::vector <field_value> *fvs) {
        return _impl->hash_get_all(key, fvs);
    }

    /// Returns all field names in the hash stored at key.
    status scylla_store::hash_keys(const std::string_view &key,
                                   std::vector <std::string> *fields) {
        return _impl->hash_keys(key, fields);
    }

    /// Returns all values in the hash stored at key.
    status scylla_store::hash_values(const std::string_view &key,
                                     std::vector <std::string> *values) {
        return _impl->hash_values(key, values);
    }

    /// Sets field in the hash stored at key to value, only if field does not yet
    /// exist. If key does not exist, a new key holding a hash is created. If field
    /// already exists, this operation has no effect.
    status
    scylla_store::hash_set_nx(const std::string_view &key, const std::string_view &field, const std::string_view &value,
                              int32_t *ret) {
        return _impl->hash_set_nx(key, field, value, ret);
    }

    /// Returns the number of fields contained in the hash stored at key.
    /// Return 0 when key does not exist.
    status scylla_store::hash_len(const std::string_view &key, int32_t *ret) {
        return _impl->hash_len(key, ret);
    }

    /// Returns the string length of the value associated with field in the hash
    /// stored at key. If the key or the field do not exist, 0 is returned.
    status scylla_store::hash_strlen(const std::string_view &key, const std::string_view &field, int32_t *len) {
        return _impl->hash_strlen(key, field, len);
    }

    /// Returns if field is an existing field in the hash stored at key.
    /// Return status::Ok() if the hash contains field.
    /// Return status::NotFound() if the hash does not contain field,
    /// or key does not exist.
    status scylla_store::hash_exists(const std::string_view &key, const std::string_view &field) {
        return _impl->hash_exists(key, field);
    }

    /// Increments the number stored at field in the hash stored at key by
    /// increment. If key does not exist, a new key holding a hash is created. If
    /// field does not exist the value is set to 0 before the operation is
    /// performed.
    status scylla_store::hash_incr_by(const std::string_view &key, const std::string_view &field, int64_t value,
                                      int64_t *ret) {
        return _impl->hash_incr_by(key, field, value, ret);
    }

    /// Increment the specified field of a hash stored at key, and representing a
    /// floating point number, by the specified increment. If the increment value
    /// is negative, the result is to have the hash field value decremented instead
    /// of incremented. If the field does not exist, it is set to 0 before
    /// performing the operation. An error is returned if one of the following
    /// conditions occur:
    ///
    /// The field contains a value of the wrong type (not a string).
    /// The current field content or the specified increment are not parsable as a
    /// double precision floating point number.
    status scylla_store::hash_incr_by_float(const std::string_view &key, const std::string_view &field,
                                            const std::string_view &by, std::string *new_value) {
        return _impl->hash_incr_by_float(key, field, by, new_value);
    }

    /// Removes the specified fields from the hash stored at key. Specified fields
    /// that do not exist within this hash are ignored. If key does not exist, it
    /// is treated as an empty hash and this command returns 0.
    status scylla_store::hash_del(const std::string_view &key, const std::vector <std::string> &fields,
                                  int32_t *ret) {
        return _impl->hash_del(key, fields, ret);
    }

    /// See SCAN for HSCAN documentation.
    status scylla_store::hash_scan(const std::string_view &key, int64_t cursor, const std::string &pattern,
                                   int64_t count, std::vector <field_value> *field_values, int64_t *next_cursor) {
        return _impl->hash_scan(key, cursor, pattern, count, field_values, next_cursor);
    }

    /// Iterate over a Hash table of fields
    /// return next_field that the user need to use as the start_field argument
    /// in the next call
    status
    scylla_store::hash_scan_x(const std::string_view &key, const std::string start_field, const std::string &pattern,
                              int64_t count, std::vector <field_value> *field_values, std::string *next_field) {
        return _impl->hash_scan_x(key, start_field, pattern, count, field_values, next_field);
    }
}  // namespace scylla